#pragma once

#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>

static int defultcap = 6;

template <class T>
class block_queue
{
private:
bool IsEmpty()
{
    return _block_queue.empty();
}

bool IsFull()
{
    return _max_cap == _block_queue.size();
}
public:
 block_queue(int cap = defultcap):_max_cap(cap)
 {
    pthread_mutex_init(&_mutex,nullptr);
    pthread_cond_init(&_p_cond,nullptr);
    pthread_cond_init(&_c_cond,nullptr);
 }

void Pop(T* out)
{
    pthread_mutex_lock(&_mutex);
    while(IsEmpty()) //用while判断防止伪唤醒
    {
        // 队列为空无法取出，进入等待
        pthread_cond_wait(&_c_cond,&_mutex);
    }

    *out = _block_queue.front();
    _block_queue.pop();

    pthread_mutex_unlock(&_mutex);
    // 当队列内元素个数小于_low_water时通知生产者线程生产
    //if(_block_queue.size() < _low_water)
    pthread_cond_signal(&_p_cond);

}

void push(const T& in)
{
    pthread_mutex_lock(&_mutex);
    while(IsFull()) // 用while判断防止伪唤醒
    {
        // 队列已满，无法存入，进入等待
        pthread_cond_wait(&_p_cond,&_mutex);
    }

    _block_queue.push(in);

    pthread_mutex_unlock(&_mutex);
    // 当队列内元素个数大于_high_water时通知消费者线程消费
    //if(_block_queue.size() > _high_water)
    pthread_cond_signal(&_c_cond);
}
 ~block_queue()
 {
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_p_cond);
    pthread_cond_destroy(&_c_cond);
 }
private:
std::queue<T> _block_queue;
pthread_mutex_t _mutex;
pthread_cond_t _p_cond; // 生产者条件变量
pthread_cond_t _c_cond; // 消费者条件变量
int _max_cap; // 最大容量

int _low_water = defultcap/3;
int _high_water = defultcap/3*2;
};